/**
 * @name Proton is a particle engine for three.js
 *
 * @class Proton
 * @param {number} preParticles input any number
 * @param {number} integrationType input any number
 * @example var proton = new Proton(200);
 */

import { Debug } from "../debug/Debug";
import { log } from "../debug/log";

import { MathUtils } from "../math/MathUtils";
import { ColorUtil } from "../utils/ColorUtil";
import { Util } from "../utils/Util";
import { THREEUtil } from "../utils/THREEUtil";


// Behaviour
import { Behaviour } from "../behaviour/Behaviour";
import { Alpha } from "../behaviour/Alpha";
import { Attraction } from "../behaviour/Attraction";
import { Color } from "../behaviour/Color";
import { Collision } from "../behaviour/Collision";
import { CrossZone } from "../behaviour/CrossZone";
import { Force } from "../behaviour/Force";
import { Gravity } from "../behaviour/Gravity";
import { RandomDrift } from "../behaviour/RandomDrift";
import { Repulsion } from "../behaviour/Repulsion";
import { Rotate } from "../behaviour/Rotate";
import { Scale } from "../behaviour/Scale";
import { Spring } from "../behaviour/Spring";


import { createSpan,Span } from "../math/Span";

import { Particle } from "./Particle";
import { Pool } from "./Pool";

import { Vector3D } from "../math/Vector3D";
import { Box } from "../math/Box";
import { ease } from "../ease/ease";
import { EventDispatcher } from "../events/EventDispatcher";
import { Emitter } from "../emitter/Emitter";
import { BehaviourEmitter } from "../emitter/BehaviourEmitter";
import { FollowEmitter } from "../emitter/FollowEmitter";

import { Initialize } from "../initialize/Initialize";
import { Body } from "../initialize/Body";
import { InitializeUtil } from "../initialize/InitializeUtil";
import { Life } from "../initialize/Life";
import { Mass } from "../initialize/Mass";
import { Position } from "../initialize/Position";
import { Rate } from "../initialize/Rate";
import { Radius } from "../initialize/Radius";
import { Velocity } from "../initialize/Velocity";

import { Polar3D } from "../math/Polar3D";
import { createArraySpan ,ArraySpan} from "../math/ArraySpan";
import { Integration } from "../math/Integration";
import { Quaternion } from "../math/Quaternion";

import { BaseRender } from "../render/BaseRender";
import { CustomRender } from "../render/CustomRender";
import { MeshRender } from "../render/MeshRender";
import { PointsRender } from "../render/PointsRender";
import { SpriteRender } from "../render/SpriteRender";
import { PUID } from "../utils/PUID";
import { BoxZone } from "../zone/BoxZone";
import { LineZone } from "../zone/LineZone";
import { MeshZone } from "../zone/MeshZone";
import { PointZone } from "../zone/PointZone";
import { SphereZone } from "../zone/SphereZone";
import { ScreenZone } from "../zone/ScreenZone";

//  看样子这种直接在 类上挂东西的写法 不太规范 打包的时候 就出问题了

class Proton  extends EventDispatcher{

    // 目前看来还是挂上去比较好 避免和three的冲突
// Behaviour
static Alpha = Alpha;
static Attraction = Attraction;
static Behaviour = Behaviour;
static Collision = Collision;
static CrossZone = CrossZone;
static Color = Color;
static Force =  Force;
static F  = Force;
static Gravity = Gravity;
static G = Gravity;
static RandomDrift = RandomDrift;
static Scale = Scale;
static Repulsion = Repulsion;
static Rotate = Rotate;
static Spring = Spring;


static Particle = Particle;
static Pool = Pool;


static Emitter = Emitter
static BehaviourEmitter = BehaviourEmitter;
static FollowEmitter = FollowEmitter;
// initialize
static Initailize = Initialize
static Body =Body ;
static InitializeUtil = InitializeUtil;
static Life = Life;
static Mass = Mass;
static Position = Position;
static P = Position;
static Radius = Radius;
static Rate = Rate
static Velocity = Velocity;
static V = Velocity;

//  math
static ArraySpan = ArraySpan;
static Box = Box;
static Integration = Integration;
static createArraySpan = createArraySpan;
static MathUtils = MathUtils;
static Polar3D = Polar3D;
static Quaternion = Quaternion;
static Span = Span;
static Vector3D = Vector3D;

// render
static Render = BaseRender;
static CustomRender = CustomRender;
static MeshRender = MeshRender;
static PointsRender = PointsRender;
static SpriteRender = SpriteRender;



// util
static ColorUtil = ColorUtil;
static THREEUtil = THREEUtil;
static PUID = PUID;
static Util = Util;

static ease = ease ;

static BoxZone = BoxZone;
static LineZone = LineZone;
static MeshZone = MeshZone;
static PointZone = PointZone;
static ScreenZone = ScreenZone ;
static SphereZone = SphereZone;

static Debug = Debug;
static log = log;








//the max particle number in pool
static POOL_MAX = 500;
static TIME_STEP = 60;
static PI = Math.PI;
static DR = Math.PI / 180;

//1:100
static MEASURE = 100;
static EULER = "euler";
static RK2 = "runge-kutta2";
static RK4 = "runge-kutta4";
static VERLET = "verlet";

static PARTICLE_CREATED = "partilcleCreated";
static PARTICLE_UPDATE = "partilcleUpdate";
static PARTICLE_SLEEP = "particleSleep";
static PARTICLE_DEAD = "partilcleDead";
static PROTON_UPDATE = "protonUpdate";
static PROTON_UPDATE_AFTER = "protonUpdateAfter";
static EMITTER_ADDED = "emitterAdded";
static EMITTER_REMOVED = "emitterRemoved";

static bindEmtterEvent = false;

  constructor(preParticles, integrationType) {
    super()
    this.preParticles = Util.initValue(preParticles, Proton.POOL_MAX);
    this.integrationType = Util.initValue(integrationType, Proton.EULER);
    this.emitters = [];
    this.renderers = [];

    this.pool = new Pool();
    Proton.integrator = new Integration(this.integrationType);
  }
  /**
   * @name add a type of Renderer
   *
   * @method addRender
   * @param {Renderer} render
   */
  addRender(renderer) {
    this.renderers.push(renderer);
    renderer.init(this);
  }

  /**
   * @name add a type of Renderer
   *
   * @method addRender
   * @param {Renderer} render
   */
  removeRender(renderer) {
    this.renderers.splice(this.renderers.indexOf(renderer), 1);
    renderer.remove(this);
  }

  /**
   * add the Emitter
   *
   * @method addEmitter
   * @param {Emitter} emitter
   */
  addEmitter(emitter) {
    this.emitters.push(emitter);
    emitter.parent = this;
    this.dispatchEvent("EMITTER_ADDED", emitter);
  }

  removeEmitter(emitter) {
    if (emitter.parent != this) return;

    this.emitters.splice(this.emitters.indexOf(emitter), 1);
    emitter.parent = null;
    this.dispatchEvent("EMITTER_REMOVED", emitter);
  }

  update($delta) {
    this.dispatchEvent("PROTON_UPDATE", this);

    var delta = $delta || 0.0167;
    if (delta > 0) {
      var i = this.emitters.length;
      while (i--) this.emitters[i].update(delta);
    }

    this.dispatchEvent("PROTON_UPDATE_AFTER", this);
  }

  /**
   * getCount
   * @name get the count of particle
   * @return (number) particles count
   */
  getCount() {
    var total = 0;
    var i,
      length = this.emitters.length;
    for (i = 0; i < length; i++) total += this.emitters[i].particles.length;
    return total;
  }

  /**
   * destroy
   * @name destroy the proton
   */
  destroy() {
    var i = 0,
      length = this.emitters.length;

    for (i; i < length; i++) {
      this.emitters[i].destroy();
      delete this.emitters[i];
    }

    this.emitters.length = 0;
    this.pool.destroy();
  }
}
// 这里又把方法都挂上去了
for (var key in ease) {
    if (key != "setEasingByName") Proton[key] = ease[key];
}










export { Proton };
